#include "ConnectionPool.h"

// 懒汉式单例
ConnectionPool* ConnectionPool::getConnectPool()
{
    static ConnectionPool pool;
    return &pool;
}

shared_ptr<MysqlConn> ConnectionPool::getConnection()
{
    unique_lock<mutex> locker(m_mutex);
    //连接池不为空
    while (m_connection.empty())
    {

        //如果还是为空就阻塞一会在重新遍历
        if (cv_status::timeout == m_cond.wait_for(locker, chrono::milliseconds(100)))
        {
            if (m_connection.empty())
            {
                continue;
            }
        }
    }
    //使用智能指针进行回收，重写它删除器的逻辑
    shared_ptr<MysqlConn> connptr(m_connection.front(), [this](MysqlConn* conn) {
        unique_lock<mutex> locker(m_mutex);
        conn->refreshAliveTime();//更新存活时间
        m_connection.push(conn);
        });

    m_connection.pop();
    m_cond.notify_all();//唤醒所有线程
    return connptr;
}

ConnectionPool::ConnectionPool()
{
    //基础配置的参数
    this->ip = "tcp://127.0.0.1:3306";
    this->user = "root";
    this->passwd = "Cyzn_123";
    this->db = "VisiGuard";
    this->minSize = 30;
    this->maxSize = 50;
    this->maxIdleTime = 300;
    //初始化最小连接对象
    for (int i = 0; i < minSize; i++)
    {
        addConnect();
    }
    //设置监听者，动态扩展连接池
    thread producter(&ConnectionPool::productConnection, this);//生产者
    thread recycler(&ConnectionPool::recycleConnection, this);//消费者
    producter.detach();
    recycler.detach();
}

ConnectionPool::~ConnectionPool()
{

    // 等待一段时间让线程退出
    this_thread::sleep_for(chrono::milliseconds(100));

    unique_lock<mutex> locker(m_mutex);
    //依次释放每一个连接对象
    while (!m_connection.empty())
    {
        MysqlConn* conn = m_connection.front();
        m_connection.pop();
        delete conn;
    }
}


void ConnectionPool::productConnection()
{
    while (true)
    {
        unique_lock<mutex> locker(m_mutex);
        while (m_connection.size() >= 1)//小于这个最小连接数时进行阻塞
        {
            m_cond.wait(locker);
        }
        addConnect();//添加新的连接对象
        m_cond.notify_all();//唤醒
    }
}

void ConnectionPool::recycleConnection()
{
    while (true)
    {
        this_thread::sleep_for(chrono::seconds(100)); // 检测间隔
        while (m_connection.size() > minSize)
        {
            MysqlConn* conn = m_connection.front();//取出队头的一个元素
            if (conn->getAliveTime() >= maxIdleTime)
            {
                m_connection.pop();//出栈
                delete conn;
            }
            else
            {
                break;
            }
        }
    }
}

void ConnectionPool::addConnect()
{
    try {
        //创建连接对象
        MysqlConn* conn = new MysqlConn;
        if (conn->Connect(ip, user, passwd, db)) 
        {
            //放入队列容器
            m_connection.push(conn);
        }
        else {
            delete conn;
            cerr << "创建数据库连接失败" << endl;
        }
    }
    catch (exception& e) {
        cerr << "创建数据库连接异常" << e.what() << endl;
    }
}